/* A wee progam to test the spangling sockets. */

/* #define _P __P */

#define SEND_SIZE 1400

#ifdef USER_STACK
#include "libusernet.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h> 
#include <time.h>
#include <sys/times.h>
#include <sys/time.h>

#define user_init() ((void)0)
#define user_socket(a,b,c) socket(a,b,c)
#define user_bind(a,b,c) bind(a,b,c)
#define user_connect(a,b,c) connect(a,b,c)
#define user_send(a,b,c,d) send(a,b,c,d)
#define user_close(a) close(a)
#define user_kill() ((void)0)
#endif


long tvdif2us(struct timeval *t0, struct timeval *t1)
{
  struct timeval tdiff;
  long us;

  tdiff.tv_sec = t1->tv_sec - t0->tv_sec;
  tdiff.tv_usec = t1->tv_usec - t0->tv_usec;
  if (tdiff.tv_usec < 0)
    tdiff.tv_sec--, tdiff.tv_usec += 1000000;

  us = ((long)tdiff.tv_sec*1000000) + tdiff.tv_usec;
  return us;
}


int main(int   argc,
	 char *argv[])
{
    int                sock;
    struct sockaddr_in raddr = {0};
    struct sockaddr_in laddr = {0};
    char               buf[SEND_SIZE];
    int                i, old_i;

    struct hostent    *he;
    int                port;
    int                ret;

    int  numsentokay = 0;
    struct timeval a, b;

    user_init();

    if(argc != 4)
    {
	fprintf(stderr, "%s: Usage: %s <l. port> <r. hostname> <r. port>\n", 
		argv[0], argv[0]);
	exit(EXIT_FAILURE);
    }

    he = gethostbyname(argv[2]);
    if(he == NULL)
    {
	fprintf(stderr, "%s: failed to look up host \"%s\", reason: ", 
		argv[0], argv[2]);
	herror(NULL);
	fprintf(stderr, "\n");
	exit(EXIT_FAILURE);	
    }
    if(he->h_addrtype != AF_INET || he->h_length != 4)
    {
	fprintf(stderr, "%s: host \"%s\" has non-IPv4 address.\n", 
		argv[0], argv[2]);
	exit(EXIT_FAILURE);
    }

    port = strtol(argv[3], NULL, 10);
    if ( errno == ERANGE || port > 65535 || port < 0 )
    {
	fprintf(stderr, "%s: port \"%s\" invalid.\n", argv[0], argv[3]);
	exit(EXIT_FAILURE);
    }
    printf("%s: sending to %s:%d.\n", 
	   argv[0], he->h_name, port);
    raddr.sin_family      = AF_INET;
    raddr.sin_addr.s_addr = *((long *)(he->h_addr_list[0]));
    raddr.sin_port        = htons(port);

    port = strtol(argv[1], NULL, 10);
    if ( errno == ERANGE || port > 65535 || port < 0 )
    {
	fprintf(stderr, "%s: port \"%s\" invalid.\n", argv[0], argv[1]);
	exit(EXIT_FAILURE);
    }
    laddr.sin_family      = AF_INET;
    laddr.sin_addr.s_addr = 0;
    laddr.sin_port        = htons(port);

    if ( (sock = user_socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
    {
	fprintf(stderr, "%s: socket failed: %s.\n",
		argv[0], strerror(errno));
	exit(EXIT_FAILURE);
    }
    printf("socket: \t%d\n", sock);

    for( i = 0; i < SEND_SIZE; i++ ) buf[i] = i+1;

    if ( (ret = user_bind(sock,
                          (struct sockaddr *)&laddr,
                          sizeof(struct sockaddr_in))) < 0 )
    {
	fprintf(stderr, "%s: bind failed: %s.\n",
		argv[0], strerror(errno));
	exit(EXIT_FAILURE);
    }
    printf("bind:\t%d\n", ret);

    if ( (ret = user_connect(sock, 
                             (struct sockaddr *)&raddr, 
                             sizeof(struct sockaddr_in))) < 0 )
    {
	fprintf(stderr, "%s: connect failed: %s.\n",
		argv[0], strerror(errno));
	exit(EXIT_FAILURE);
    }
    printf("connect: \t%d\n", ret);    

    i = old_i = 0;
    gettimeofday(&a, NULL);
    while ( 1 )
    {
        *((int *)buf) = i++;
	ret = user_send(sock, buf, SEND_SIZE, 0);
        printf("Sending...\n");
	if ( ret < 0 )
	{
            fprintf(stderr, "%s: send failed: %s.\n",
                    argv[0], strerror(errno));
            exit(EXIT_FAILURE);
	}
        else if ( ((i % 5000) == 0) && 
                  (tvdif2us(&a, (gettimeofday(&b, NULL), &b)) > 1000000) )
        {
            /*
             * This bandwidth estimator should output once a second has passed,
             * and a multiple of 5000 packets have been sent.
             */
            printf("%s: %.1f Mb/s, %dK pkts\n", argv[3],
                   (((float)(i-old_i)*SEND_SIZE*8)/
                    ((float)tvdif2us(&a, &b))),
                   (i - old_i)/1000);
            gettimeofday(&a, NULL);
            old_i = i;
        }
    }

    ret = user_close(sock);
    printf("close: \t\t%d\n", ret);
    if(ret < 0)
    {
	fprintf(stderr, "%s: close failed: %s.\n",
		argv[0], strerror(errno));
	exit(EXIT_FAILURE);
    }		       

    printf("Killing stack...\n");
    user_kill();
    printf("Dead\n");

    exit(EXIT_SUCCESS);
} 

/* End of $RCSFile$ */
